//
// Created by admin on 2024/7/15.
//

#include "Wire.h"

TwoWire::TwoWire(void *i2c, size_t bufferSize) :
	_i2c(i2c),
	txBuffer(bufferSize),
	rxBuffer(bufferSize) {
}

TwoWire::~TwoWire() {
}

bool TwoWire::begin(uint8_t devAddr, int sda, int scl) {
	//    pinMode(sda, OUTPUT);
	//    pinMode(scl, INPUT);

	_devAddr = devAddr;
	return true;
}

int TwoWire::readByte(uint16_t devAddr, uint16_t regAddr, uint8_t *data) {
	return readBytes(devAddr, regAddr, data, 1);
}

int TwoWire::readBytes(uint16_t devAddr, uint16_t regAddr, uint8_t *data, uint8_t length) {
	if (data == nullptr) return I2C_UNKNOWN;

	if (requestFromRegister(devAddr, regAddr, I2C_8BIT_ADDR, length) != length) {
		return I2C_ERROR;
	}
	read(data, length);
	return I2C_OK;
}

int TwoWire::writeByte(uint16_t devAddr, uint16_t regAddr, uint8_t data) {
	return writeBytes(devAddr, regAddr, &data, 1);
}

int TwoWire::writeBytes(uint16_t devAddr, uint16_t regAddr, uint8_t *data, uint8_t length) {
	beginTransmission(devAddr, regAddr, I2C_8BIT_ADDR);
	write(data, length);

	if (endTransmission() < 1) {
		return I2C_ERROR;
	}

	return I2C_OK;
}

void TwoWire::beginTransmission(uint16_t devAddr, uint16_t regAddr, uint8_t addrSize) {
	nonStop   = false;
	_devAddr  = devAddr;
	_regAddr  = regAddr;
	_addrSize = addrSize;
}

int TwoWire::endTransmission(bool sendStop) {
	txBuffer.pullStart();
	size_t txLength = txBuffer.getPullLineSize();

	int write = 0;
	if (I2C_OK == I2C_REG_WRITE(_i2c, _devAddr, _regAddr, _addrSize, txBuffer.tail(), txLength)) {
		write = txLength;
	}
	txBuffer.pullEnd(write);

	if (write > 0) {
		txBuffer.flush();
	}
	return write;
}

size_t TwoWire::requestFrom(uint16_t devAddr, size_t size, bool sendStop) {
	rxBuffer.pushStart();
	size_t rxLength = rxBuffer.getPullLineSize();

	if (size > rxLength) size = rxLength;

	int read = 0;
	if (I2C_OK == I2C_READ(_i2c, devAddr, rxBuffer.head(), size, sendStop)) {
		read = size;
	}
	rxBuffer.pushEnd(read);

	if (read) {
		rxBuffer.flush();
	}

	return read;
}

size_t TwoWire::requestFromRegister(uint16_t devAddr, uint16_t regAddr, uint8_t addrSize,
									size_t length) {
	rxBuffer.pushStart();
	size_t size = rxBuffer.getPushLineSize();

	if (length > size) length = size;

	int read = 0;
	if (I2C_OK == I2C_REG_READ(_i2c, devAddr, regAddr, addrSize, rxBuffer.head(), length)) {
		read = length;
	}
	rxBuffer.pushEnd(read);

	if (read > 0) {
		rxBuffer.flush();
	}

	return read;
}

int TwoWire::read() {
	uint8_t data[1];
	read(data, 1);
	return data[0];
}

size_t TwoWire::read(uint8_t *buffer, size_t length) {
	return rxBuffer.pull(buffer, length);
}

size_t TwoWire::write(uint8_t data) {
	return write(&data, 1);
}

size_t TwoWire::write(uint8_t *data, size_t size) {
	return txBuffer.push(data, size);
}

void TwoWire::irqHandler(void *i2c, int event, uint32_t idleRxCount) {
	if (i2c != _i2c) {
		return;
	}

	// if (event & I2C_EVENT_TX_TC) {
	// 	writeToI2c(idleRxCount);
	// }
}

bool TwoWire::writeToI2c(uint32_t written_len) {
	txBuffer.pullEnd(written_len);
	txBuffer.flush();

	return true;
}

#if I2C_1_ENABLE
TwoWire Wire(I2C_1_OBJ);
#endif

#if I2C_2_ENABLE
TwoWire Wire2(I2C_2_OBJ);
#endif

extern "C" void I2C_EVENT_HANDLER(void *i2c, int event, uint32_t rxCount) {
#if I2C_1_ENABLE
	Wire.irqHandler(i2c, event, rxCount);
#endif

#if I2C_2_ENABLE
	Wire2.irqHandler(i2c, event, rxCount);
#endif
}
